/*
* Conditions Of Use
*
* This software was developed by employees of the Sigmatrix(Beijing) Corporation.
* This software is provided by sigmatrix as a service and is expressly
* provided "AS IS."  Sigmatrix MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY.  Sigmatrix does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
* Permission to use this software is contingent upon your acceptance
* of the terms of this agreement.
*
*/
package com.sigmatrix.h5.web.controller;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.validation.Valid;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.sigmatrix.h5.dto.InStorageData;
import com.sigmatrix.h5.entity.SyncTask;
import com.sigmatrix.h5.enums.ResponseEnum;
import com.sigmatrix.h5.enums.SyncTaskTypeEnum;
import com.sigmatrix.h5.exception.ServiceException;
import com.sigmatrix.h5.page.PageBean;
import com.sigmatrix.h5.response.Response;
import com.sigmatrix.h5.service.InStorageService;
import com.sigmatrix.h5.service.SyncTaskService;
import com.sigmatrix.h5.utils.Cons;
import com.sigmatrix.h5.utils.ThreadPool;
import com.sigmatrix.h5.utils.Utils;
import com.sigmatrix.h5.utils.VerifyUtil;
import com.sigmatrix.h5.web.controller.common.BaseController;
import com.sigmatrix.h5.web.vo.BaseInStorageVo;
import com.sigmatrix.h5.web.vo.InStorageAddVo;
import com.sigmatrix.h5.web.vo.InStorageListVo;
import com.sigmatrix.h5.web.vo.InStoragePageVo;
import com.sigmatrix.h5.web.vo.InStorageUpLoad;
import com.sigmatrix.h5.web.vo.InStorageUpLoadVo;
import com.sigmatrix.h5.web.vo.SyncTaskVo;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * @ClassName: InStorageController
 * @Description: 入库单控制器
 * @author youjun
 * @date 2017-07-06 14:18:28
 */
@Api(tags="入库相关接口")
@RestController
@RequestMapping("/app/instorage")
public class InStorageController extends BaseController {
	
	/**logger record*/
	private static final Logger LOGGER = LoggerFactory.getLogger(InStorageController.class);
	
	/**入库业务层接口*/
	@Autowired
	private transient InStorageService inStorageService;
	
	/**异步任务业务层接口*/
	@Autowired
	private transient SyncTaskService syncTaskService;

	/**
	 * @Title: getInStoragePageList
	 * @Description: 分页查询入库单列表
	 * @return ModelAndView
	 * @author youjun 
	 * @date 2017-07-06 14:18:28
	 * @param request
	 * @param vo
	 */
	@ApiOperation(value="分页查询")
	@PostMapping("/pagelist")
	public Response getInStoragePageList(
			@Valid @RequestBody final InStoragePageVo vo,final BindingResult result) {

		final String channelType = inStorageService.getChannelTypeDesc(vo.getChannelType());
		try {
			LOGGER.info("{}入库单据分页查询列表接口开始...{}", channelType,JSONObject.toJSONString(vo));
			final Response validateResponse = validateParams(vo);
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			final Map<String, Object> map = new HashMap<String, Object>();
			final PageBean<InStorageData> pageBean = 
					new PageBean<InStorageData>(vo.getPageNo(),vo.getPageSize());
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("{}入库单据分页查询列表接口参数验证失败{}", channelType, errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			final Response resultResponse = inStorageService.findListByPage(pageBean, vo, map);
			LOGGER.info("{}入库单据分页查询列表接口返回结果:{}", channelType, JSONObject.toJSONString(resultResponse));
			return resultResponse;
		} catch (ServiceException e) {
			LOGGER.error("{}入库单据分页查询列表接口失败", e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}
	
	
	/**
	 * 
	 *@Title: uploadInStorage
	 *@Description:返利上传
	 *@return Response
	 *@author gaomingkai
	 *@date 2017年12月19日 下午4:28:19
	 *@param storageUpLoad
	 *@return
	 */
	@ApiOperation(value="返利上传")
	@PostMapping(value="/receipt")
	public Response receiptInStorage(@RequestBody final InStorageUpLoad inStorageUpLoad) {
		try {
			LOGGER.info("上传接口请求={}",JSONObject.toJSONString(inStorageUpLoad));
			//参数校验
			final Response validateResponse = inStorageService.verification(inStorageUpLoad);
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			
			//类似酒鬼酒定制需求一级经销商不做库存的增减
			Response checkResponse = inStorageService.checkdealer(inStorageUpLoad);
			if(checkResponse.getCode() == Cons.RESPONSE_CODE_SUCCESS) {
				return new Response(ResponseEnum.SUCCESS);
			}
			
			//数据处理
			final Response resultResponse = inStorageService.receipt(inStorageUpLoad);
			LOGGER.info("上传入库单接口返回结果={}",JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e) {
			LOGGER.error("上传入库单接口失败", e);
			return new Response(ResponseEnum.EXCEPTION,e.getMessage());
		}
	}
	
	/**
	 * 
	 *@Title: goodsInStorage
	 *@Description:(酒鬼酒定制上传接口)  企业发送一级经销商
	 *@return Response 
	 *@author gaomingkai
	 *@date 2018年2月5日 下午4:07:16
	 *@param inStorageUpLoad
	 *@return
	 */
	@ApiOperation(value="企业上传")
	@PostMapping(value="/goods")
	public Response goodsInStorage(@RequestBody final InStorageUpLoad inStorageUpLoad) {
		try {
			LOGGER.info("企业发送一级经销商上传接口请求={}",JSONObject.toJSONString(inStorageUpLoad));
			//参数校验
			final Response validateResponse = inStorageService.check(inStorageUpLoad);
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			//数据处理
			final Response resultResponse = inStorageService.goods(inStorageUpLoad);
			LOGGER.info("上传入库单接口返回结果={}",JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e) {
			LOGGER.error("上传入库单接口失败", e);
			return new Response(ResponseEnum.EXCEPTION,e.getMessage());
		}
	}

	/**
	 *@Title: uploadInStorage
	 *@Description: 上传入库单接口
	 *@return Response
	 *@author youjun
	 *@date 2017年8月14日 下午6:00:02
	 *@param reqeust
	 *@param vo
	 *@param result
	 */
	@ApiOperation(value="上传")
	@PostMapping(value="/upload")
	public Response uploadInStorage(@Valid @RequestBody final InStorageUpLoadVo vo, 
			final BindingResult result) {
		
		final String channelTypeDesc = inStorageService.getChannelTypeDesc(vo.getChannelType());
		LOGGER.info("上传{}入库单接口开始", channelTypeDesc);
		try {
			LOGGER.info("请求参数为:{}", JSONObject.toJSONString(vo));
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("上传{}入库单列表接口参数验证失败{}", channelTypeDesc, errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			
			final String enterpriseCode = vo.getEnterpriseCode();
			SyncTaskVo syncTaskVo = new SyncTaskVo();
			syncTaskVo.setCreateTime(new Date());
			syncTaskVo.setEnterpriseCode(enterpriseCode );
			syncTaskVo.setRequestParams(JSONObject.toJSONString(vo));
			syncTaskVo.setStatus(Cons.SYNC_TASK_STATUS_NO_HANDLE); // 待处理
			syncTaskVo.setType(getType(vo));
			final int syncTaskId = syncTaskService.save(syncTaskVo);
			
			
			// 异步处理
			vo.setSyncTaskId(syncTaskId);
//			outStorageService.upload(outStorageVo);
			
			ThreadPool.executor.submit(() -> {
				try {
					inStorageService.upload(vo);
				} catch(Exception e) {
					SyncTask updateSyncTask = new SyncTask();
					updateSyncTask.setIsSuccess(Cons.SYNC_TASK_FAIL);
					updateSyncTask.setResponseCode(Cons.RESPONSE_CODE_DATA_EXCEPTION+"");
					updateSyncTask.setResponseMsg(e.getMessage());
//					updateSyncTask.setResponseResult();
					updateSyncTask.setTypeSign(vo.getOrderCode());
					updateSyncTask.setStatus(Cons.SYNC_TASK_STATUS_HANDLE_FINISH); // 处理完成
					try {
						syncTaskService.updateByCondition(enterpriseCode, syncTaskId, updateSyncTask);
					} catch (ServiceException e1) {
						LOGGER.error("异步处理失败", e);
					}
				}
			});
			
			Map<String, Object> resultMap = new HashMap<String, Object>();
			resultMap.put("syncTaskId", syncTaskId);
			final Response resultResponse = new Response(ResponseEnum.SUCCESS, resultMap);
			LOGGER.info("上传{}入库单接口返回结果{}", channelTypeDesc, JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e) {
			LOGGER.error("上传{}入库单接口失败", channelTypeDesc, e);
			return new Response(ResponseEnum.EXCEPTION,e.getMessage());
		}
	}
	
	
	private short getType(final InStorageUpLoadVo vo) {
		short type = 0;
		if (vo.getChannelType() == 1) {
			type = SyncTaskTypeEnum.IN_CHANNEL_TYPE_PRO.getId().shortValue();
		}
		if (vo.getChannelType() == 2) {
			type = SyncTaskTypeEnum.IN_CHANNEL_TYPE_RET.getId().shortValue();
		}
		if (vo.getChannelType() == 3) {
			type = SyncTaskTypeEnum.IN_CHANNEL_TYPE_OTH.getId().shortValue();
		}
		if (vo.getChannelType() == 4) {
			type = SyncTaskTypeEnum.IN_CHANNEL_TYPE_REC.getId().shortValue();
		}
		return type;
	}
	
	/**
	 *@Title: save
	 *@Description: 保存入库单
	 *@return Response
	 *@date 2017年9月12日 上午1:25:32
	 *@param result
	 *@param vo
	 */
	@ApiOperation(value="新增")
	@PostMapping("/save")
	public Response save(@Valid @RequestBody final InStorageAddVo vo,final BindingResult result) {

		final String channelTypeDesc = inStorageService.getChannelTypeDesc(vo.getChannelType());
		try {
			LOGGER.info("新增{}入库单接口开始...{}", channelTypeDesc,JSONObject.toJSONString(vo));
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("{}参数验证失败{}", channelTypeDesc, errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			final Response resultResponse = inStorageService.save(vo);
			LOGGER.info("新增{}入库单接口返回结果{}", channelTypeDesc, JSONObject.toJSONString(resultResponse));
			return resultResponse;
		} catch (ServiceException e) {
			LOGGER.error("新增{}入库单失败", channelTypeDesc, e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}
	
	
	@ApiOperation(value = "单据详情")
	@PostMapping("/detail")
	public Response getDetail(@Valid @RequestBody final BaseInStorageVo vo,final BindingResult result) {
		try{
			LOGGER.info("获取入库单单据详情接口开始...{}",JSONObject.toJSONString(vo));
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("入库单单据详情接口参数验证失败{}", errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			if(Utils.isEmpty(vo.getInStorageId())){
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "入库单id不可以为空");
			}
			final Response resultResponse = inStorageService.findById(vo.getEnterpriseCode(), vo.getInStorageId());
			LOGGER.info("获取入库单单据详情接口返回结果:{}", JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e){
			LOGGER.error("获取入库单单据详情接口失败", e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}

	/**
	 *@Title: close
	 *@Description: 关闭入库单
	 *@return Response
	 *@author youjun
	 *@date 2017年8月23日 下午5:23:12
	 *@param request
	 *@param vo
	 */
	@ApiOperation(value = "关闭")
	@PostMapping(value="/close")
	public Response close(@Valid @RequestBody final BaseInStorageVo vo,final BindingResult result) {
		try{
			LOGGER.info("关闭入库单单据接口开始...{}",JSONObject.toJSON(vo));
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("关闭入库单接口参数验证失败{}", errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			final Response resultResponse = inStorageService.colse(vo);
			LOGGER.info("关闭入库单单据接口接口返回结果:{}", JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e){
			LOGGER.error("关闭入库单单据接口接口失败", e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}
	

	@ApiOperation(value = "同步")
	@PostMapping("/synclist")
	public Response synclist(@Valid @RequestBody final InStorageListVo vo,final BindingResult result) {
		LOGGER.info("获取{}入库单列表接口开始...",JSONObject.toJSON(vo));
		//渠道描述
		final String channelTypeDesc = inStorageService.getChannelTypeDesc(vo.getChannelType());
		try{
			if (result.hasErrors()) {
				final String errInfo = result.getAllErrors().get(0).getDefaultMessage();
				LOGGER.error("获取{}入库单列表接口参数验证失败{}", channelTypeDesc, errInfo);
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, errInfo);
			}
			final Response resultResponse = inStorageService.findForSync(vo);
			LOGGER.info("获取{}入库单列表接口返回数据:{}", channelTypeDesc, JSONObject.toJSONString(resultResponse));
			return resultResponse;
		}catch(Exception e) {
			LOGGER.error("获取{}入库单列表接口失败", channelTypeDesc, e);
			return new Response(ResponseEnum.EXCEPTION);
		}
	}
	
	
	/**
	 *@Title: validateParams
	 *@Description: TODO()
	 *@return Response
	 *@author youjun
	 *@date 2017年7月14日 下午2:02:27
	 *@param inStorageVo
	 *@return
	 */
	private Response validateParams(final InStoragePageVo inStorageVo) {
		
		final Response validateBasic = validateBasicParams(inStorageVo, true);
		if(validateBasic.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
			return validateBasic;
		}
		// 验证日期
		final String createTimeStart = inStorageVo.getCreateTimeStart();
		final String createTimeEnd = inStorageVo.getCreateTimeEnd();
		if(StringUtils.isNotBlank(createTimeStart)) {
			if(!VerifyUtil.isValidDate(createTimeStart)) {
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "创建时间开始段格式有误");
			}
		}
		if(StringUtils.isNotBlank(createTimeEnd)) {
			if(!VerifyUtil.isValidDate(createTimeEnd)) {
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "创建时间结束段格式有误");
			}
		}
		return new Response(ResponseEnum.SUCCESS);
	}
	
	
}
